---
title: WSP - WebSocket 联调测试
layout: default_footer
keywords: [WSP,websocket,websocket联调工具,websocket测试]
description: websocket 在线联调、测试工具。手动发送、接收 websocket 消息。可以编辑保存快捷消息，方便相同消息多次发送。
---

{% raw %}
<div id="main" class="uk-height-1-1" style="min-height: 440px; min-width: 1098px;">

<div id="msg-box" class="uk-panel uk-panel-box uk-overflow-container uk-height-1-1"
     style="display:inline-block;width:48%;padding: 0;">
    <div v-for="msg in msg2Show" :class="{
            'uk-text-muted  uk-text-center': msg.type == 'sys',
            'uk-alert': msg.type == 'biz-recv',
            'uk-alert-success': msg.type == 'biz-send',
        }"
        style="padding: 0 10px 10px 10px;margin-bottom: 10px;">

        <span v-if="msg.type == 'sys'" style="color: #aaa;">
            {{ msg.timestamp }}: {{ msg.content }}
        </span>

        <span v-if="msg.type == 'biz-recv' || msg.type == 'biz-send'">
            {{ msg.timestamp }}  &nbsp;&nbsp;
        </span>

        <a v-if="msg.type == 'biz-recv'" class="copy-btn">复制消息</a>
        <pre v-if="msg.type == 'biz-recv' || msg.type == 'biz-send'"  
             style="background: transparent;
                    padding: 0; 
                    margin: 0;"><code>{{ msg.content }}</code></pre>
    </div>
</div>

<div id="operation-box" style="width:49%;float:right;">
    <div class="uk-form" >
        <div class="uk-form-row">
            <input style="width:66%;" type="text" v-model="url" placeholder="WebSocket 服务器地址"> 
            <button class="uk-button uk-button-primary" :disabled="connected" @click="doConnect()"
                    :style="buttonSuccess">
                    <i id="connecting-spinner" class="uk-icon-spin uk-icon-spinner" style="display: none;"></i>
                    <span v-show="connected">已</span>连接
                    <span v-show="!connected"> (ctrl+o)</span>
            </button>
            <button class="uk-button uk-button-primary" :disabled="!connected" @click="doDisconnect()"
                    style="float:right;">断开</button>
        </div>
        <div v-show="url.startsWith('ws://')" data-uk-alert class="uk-alert-warning" 
            style="width:fit-content;padding: 4px 6px;">
            <span>连接 ws:// 开头的服务器，可能需要允许浏览器加载不安全的脚本。</span> 
            <a class="uk-alert-close uk-close"></a>
        </div>
        <div class="uk-form-row" style="margin-top: 15px;">
            <textarea class="uk-width-1-1" type="text" v-model="msg2Send" :disabled="!connected"
                onkeydown="onkeydown_tab(this)"
                style="min-height: 150px;" placeholder="要发送的消息内容，可输入 tab 键（4个空格）。"></textarea>
        </div>
        <div class="uk-form-row">
            <button class="uk-button uk-button-primary" :disabled="!connected" @click="doSend()" 
                    style="float: right;">发送 (ctrl+enter)</button>
        </div>
    </div>

    <!-- 快捷消息 -->
    <div class="uk-form">
        <div class="uk-form-row" style="margin-top: 15px;">
            <textarea class="uk-width-1-1" type="text" v-model="myMsg1" 
                style="min-height: 70px;" onkeydown="onkeydown_tab(this)" 
                placeholder="快捷消息1，内容会保存到 localStorage，方便下次使用"></textarea>
        </div>
        <div class="uk-form-row" style="margin-top: 5px;">
            <textarea class="uk-width-1-1" type="text" v-model="myMsg2" 
                style="min-height: 70px;" onkeydown="onkeydown_tab(this)" 
                placeholder="快捷消息2，内容会保存到 localStorage，方便下次使用"></textarea>
        </div>
        <!-- <div class="uk-form-row" style="margin-top: 5px;">
            <textarea class="uk-width-1-1" type="text" v-model="myMsg3" 
                style="min-height: 50px;" onkeydown="onkeydown_tab(this)" 
                placeholder="快捷消息3，内容会保存到 localStorage，方便下次使用"></textarea>
        </div> -->
        <div class="uk-form-row">
            <!-- <button class="uk-button uk-button-primary" :disabled="!connected" @click="doSend3()" 
                style="float: right;">发送消息3 (ctrl+3)</button> -->
            <button class="uk-button uk-button-primary" :disabled="!connected" @click="doSend2()" 
                    style="float: right;margin-left:15px;">发送消息2 (ctrl+2)</button>
            <button class="uk-button uk-button-primary" :disabled="!connected" @click="doSend1()" 
                    style="float: right;margin-left:15px;">发送消息1 (ctrl+1)</button>

            <!-- <div class="uk-button-dropdown" style="float:right;" data-uk-dropdown="{pos:'top-right'}">
                <button id="alipay-red-bao-button" class="uk-button" 
                        onmouseover="viewAlipayRedBao()">支付宝红包</button>
                <div class="uk-dropdown uk-dropdown-small" style="width:240px;">
                    <img src="//cdn.apihub.net/img/alipay-red-bao.jpeg" alt="alipay 红包码">
                </div>
            </div> -->
        </div>
    </div>
</div>

</div>
{% endraw %}

<style>
pre, code {
    word-wrap: break-word;
    white-space: pre-wrap;
    font-family: Consolas, monospace;
}
</style>

<script src="//cdn.apihub.net/js/clipboard.min.js"></script>
<script>
    new ClipboardJS('.copy-btn', {
        target: function(trigger) {
            return trigger.nextElementSibling;
        }
    }).on('success', function(event) {
        event.clearSelection()
        UIkit.notify({
            message : '已复制',
            status  : 'success',
            timeout : 1000,
            pos     : 'top-right'
        })
    })
    hotkeys('ctrl+o,command+o', function(event,handler) {
        vm_wsp.doConnect()
    })
    hotkeys('ctrl+enter', function(event,handler) {
        vm_wsp.doSend()
    })
    hotkeys('ctrl+1', function(event,handler) {
        vm_wsp.doSend1()
    })
    hotkeys('ctrl+2', function(event,handler) {
        vm_wsp.doSend2()
    })
    hotkeys('ctrl+3', function(event,handler) {
        vm_wsp.doSend3()
    })
    function formatTime(time) {
        if (!time) {
            time = new Date()
        }
        let result = ''
        result += time.getHours() < 10 ? "0" + time.getHours()  + ':' : time.getHours() + ':'
        result += time.getMinutes() < 10 ? "0" + time.getMinutes()  + ':' : time.getMinutes() + ':'
        result += time.getSeconds() < 10 ? "0" + time.getSeconds() : time.getSeconds()
        return result
    }
    function onkeydown_tab(ele) {
        if (event.keyCode == 9) {
            let start = ele.selectionStart
		    let end = ele.selectionEnd
            ele.value = ele.value.substring(0, start) + "    " + ele.value.substring(end)
            ele.selectionStart = start + 4
            ele.selectionEnd = start + 4
            event.returnValue = false;
        }
    }

    if (localStorage.alipayRedBaoNeedShow != '0') {
        $('#alipay-red-bao-button').show()
        if (new Date().setHours(0,0,0,0) < localStorage.alipayRedBaoViewTime
            && localStorage.alipayRedBaoViewTime < new Date().setHours(23,59,59,0)) {
            $('#alipay-red-bao-button').removeClass('red-point-button')
        } else {
            $('#alipay-red-bao-button').addClass('red-point-button')
        }
    }
    function viewAlipayRedBao () {
        localStorage.alipayRedBaoViewTime = new Date().getTime()
        $('#alipay-red-bao-button').removeClass('red-point-button')
    }
</script>

<script>
var vm_wsp = new Vue({
    el: '#main',
    data: {
        url: localStorage.wsp_url ? localStorage.wsp_url :'wss://ws2s.feling.net/',
        connected: false,
        msg2Send: '',
        msg2Show: [
            {
                type: "sys", // "sys"、"biz-recv"、"biz-send"
                timestamp: formatTime(),
                content: '这里是历史消息窗口'
            }
        ],
        wsConnection: {},
        myMsg1: localStorage.wsp_myMsg1 ? localStorage.wsp_myMsg1 : '{"command":"connect","host":"ip.feling.net","port":80}',
        myMsg2: localStorage.wsp_myMsg2 ? localStorage.wsp_myMsg2 : '{\n    "command": "send",\n    "data": "GET / HTTP/1.1\\r\\nHost: ip.feling.net\\r\\n\\r\\n" }',
        myMsg3: localStorage.wsp_myMsg3 ? localStorage.wsp_myMsg3 : '',
    },
    methods: {
        doConnect () {
            if (this.connected) {
                UIkit.notify({
                    message : '请先断开当前连接',
                    status  : 'warning',
                    timeout : 3000,
                    pos     : 'top-right'
                })
                return
            }
            if (!this.url.startsWith('ws://') && !this.url.startsWith('wss://')) {
                UIkit.notify({
                    message : '无效的服务器地址',
                    status  : 'warning',
                    timeout : 3000,
                    pos     : 'top-right'
                })
                return
            }
            $('#connecting-spinner').show()
            this.wsConnection = new WebSocket(this.url)
            this.wsConnection.onopen = () => {
                this.connected = true
                $('#connecting-spinner').hide()
                this.msg2Show.push({
                    type: "sys",
                    timestamp: formatTime(),
                    content: '连接成功 (' + this.url +')'
                })
                $("#msg-box").animate({scrollTop:$("#msg-box").prop("scrollHeight")}, 400)
            }
            this.wsConnection.onmessage = (event) => {
                this.msg2Show.push({
                    type: "biz-recv",
                    timestamp: formatTime(),
                    content: event.data
                })
                $("#msg-box").animate({scrollTop:$("#msg-box").prop("scrollHeight")}, 400)
            }
            this.wsConnection.onclose = () => {
                this.connected = false
                $('#connecting-spinner').hide()
                this.msg2Show.push({
                    type: "sys",
                    timestamp: formatTime(),
                    content: '连接已断开 (' + this.url +')'
                })
                $("#msg-box").animate({scrollTop:$("#msg-box").prop("scrollHeight")}, 400)
            }
        },
        doDisconnect () {
            this.wsConnection.close()
        },
        doSend () {
            if (!this.connected) {
                UIkit.notify({
                    message : '请先连接服务器',
                    status  : 'warning',
                    timeout : 3000,
                    pos     : 'top-right'
                })
                return
            }
            this.wsConnection.send(this.msg2Send)
            this.msg2Show.push({
                type: "biz-send",
                timestamp: formatTime(),
                content: this.msg2Send
            })
        },
        doSend1 () {
            if (!this.connected) {
                UIkit.notify({
                    message : '请先连接服务器',
                    status  : 'warning',
                    timeout : 3000,
                    pos     : 'top-right'
                })
                return
            }
            this.wsConnection.send(this.myMsg1)
            this.msg2Show.push({
                type: "biz-send",
                timestamp: formatTime(),
                content: this.myMsg1
            })
        },
        doSend2 () {
            if (!this.connected) {
                UIkit.notify({
                    message : '请先连接服务器',
                    status  : 'warning',
                    timeout : 3000,
                    pos     : 'top-right'
                })
                return
            }
            this.wsConnection.send(this.myMsg2)
            this.msg2Show.push({
                type: "biz-send",
                timestamp: formatTime(),
                content: this.myMsg2
            })
        },
        doSend3 () {
            if (!this.connected) {
                UIkit.notify({
                    message : '请先连接服务器',
                    status  : 'warning',
                    timeout : 3000,
                    pos     : 'top-right'
                })
                return
            }
            this.wsConnection.send(this.myMsg3)
            this.msg2Show.push({
                type: "biz-send",
                timestamp: formatTime(),
                content: this.myMsg3
            })
        }
    },
    computed: {
        statusName () {
            return this.connected ? '已连接' : '未连接 X'
        },
        buttonSuccess () {
            return {
                backgroundColor: this.connected ? '#8cc14c' : '#35b3ee',
                color: "#fff",
            }
        },
    },
    watch: {
        url: function (val) {
            localStorage.wsp_url = val
        },
        myMsg1: function (val) {
            localStorage.wsp_myMsg1 = val
        },
        myMsg2: function (val) {
            localStorage.wsp_myMsg2 = val
        },
        myMsg3: function (val) {
            localStorage.wsp_myMsg3 = val
        },
    }
})
</script>